iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
自我挑戰組

探索 Spring Boot Doc系列 第 25

Spring AbstractFailureAnalyzer 實例

  • 分享至 

  • xImage
  •  

下方為實際的專案,再引入的 spring-boot package 之中,在 /META-INF 之下 spring.factories 之中,搜尋 FailureAnalyzer 就可以看到 boot 官方實作的各類的 FailureAnalyzer

https://ithelp.ithome.com.tw/upload/images/20231009/20161770mvAd4S1wAc.png

隨意開任一個 Test ,在其中貼上任一從上述spring.factories 內複製的類別完整路徑,
在 command + 左鍵點擊類別名稱,透過 IDE 反向打開這個類別 (此處筆者的作業系統是 macOS, IDE 是 Intellij ,但 Windows 系統和其他 IDE 也有類似的功能)

https://ithelp.ithome.com.tw/upload/images/20231009/20161770rrSPjm6bnz.png

首先關注在 NoSuchMethodFailureAnalyzer的類別宣告
https://ithelp.ithome.com.tw/upload/images/20231009/201617702ZSWfGeJEy.png

根據 AbstractFailureAnalyzer 文件提到, AbstractFailureAnalyzer<T extends Throwable>
內要指定一個 Throwable 的一個子類別,上述指定 NoSuchMethodError; 這裡使用者在自定義上面可以選擇任意的Exception,畢竟所有的Exception 自然是 Throwable 的子類。

https://ithelp.ithome.com.tw/upload/images/20231009/20161770kE9RWNC2Tn.png

protected final <E extends Throwable>E findCause(Throwable failure, Class type)
是一個 final 方法,繼承 AbstractFailureAnalyzer 的類別不得實作

@SuppressWarnings("unchecked")
	protected final <E extends Throwable> E findCause(Throwable failure, Class<E> type) {
		while (failure != null) {
			if (type.isInstance(failure)) {
				return (E) failure;
			}
			failure = failure.getCause();
		}
		return null;
	}

單看這個方法內容,可以看出是將AbstractFailureAnalyzer<T extends Throwable> 中的 T 去做轉型,轉成另一個參數 Class type ,那…這一個類別E又從哪裡提供?

這時就要回到 FailureAnalysis analyze(Throwable failure) ,是來自 FailureAnalyzer 的方法,由 AbstractFailureAnalyzer 本身就有實作 。

@Override
	public FailureAnalysis analyze(Throwable failure) {
		T cause = findCause(failure, getCauseType());
		return (cause != null) ? analyze(failure, cause) : null;
	}

從實作內容可以看到,剛剛尋找的來源 Class Type 就是由 getCaueType() 方法所提供。
由 getCauseType() 方法的註解可以看到,回傳由 analyzer 處理的造成錯誤的類型(cause type) 。
https://ithelp.ithome.com.tw/upload/images/20231009/20161770Q4tV7hP6TX.png

那其實使用者只需要自定義唯一的方法,這就是AbstractFailureAnalyzer 的抽象方法
protected abstract FailureAnalysis analyze(Throwable rootFailure, T cause)

這裡我們來臨摹 Spring 官方 NoSuchMethodError 是怎麼寫的

@Override
	protected FailureAnalysis analyze(Throwable rootFailure, NoSuchMethodError cause) {
		NoSuchMethodDescriptor callerDescriptor = getCallerMethodDescriptor(cause);
		if (callerDescriptor == null) {
			return null;
		}
		NoSuchMethodDescriptor calledDescriptor = getNoSuchMethodDescriptor(cause.getMessage());
		if (calledDescriptor == null) {
			return null;
		}
		String description = getDescription(callerDescriptor, calledDescriptor);
		String action = getAction(callerDescriptor, calledDescriptor);
		return new FailureAnalysis(description, action, cause);
	}

看樣最後三行,透過 callerDescriptor 、calledDescriptor 去產出錯誤的描述(description)、造成的起因(action),再將這兩者以及 NoSuchMethodError 去產生失敗分析(FailureAnalysis) 。

那 callerDescriptor、calledDescriptor 這兩個又與什麼相關呢?
callerDescriptor 從產生方法 getCallerMethodDescriptor 可以看出他是在分析 NoSuchMethodError 的 StackTraceElement ; 類似地從 getNoSuchMethodDescriptor 以及其之下包覆的方法,可以看到
他是將 NoSuchMethodError 的 Message 去做整理。

https://ithelp.ithome.com.tw/upload/images/20231009/20161770nnz1FZfSAC.png

參考資料
Create a Custom FailureAnalyzer
https://www.baeldung.com/spring-boot-failure-analyzer


上一篇
Doc 18.1.1. Create Your Own FailureAnalyzer
下一篇
Doc 7.1.2. Lazy Initialization
系列文
探索 Spring Boot Doc30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言